package asapIs134CK.womi.client.games.logoGame.froggitTheFrog;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import asapIs134CK.womi.client.games.SuccessHandler;
import asapIs134CK.womi.client.games.logoGame.utils.Position;

import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;

public class FroggitGame {
	private FroggitWorld _world;
	private List<FroggitAction> _passedActions;
	private Queue<FroggitAction> _incommingActions;
	private FroggitMyFrog _littleFrog;
	private List<SuccessHandler> _successListener;

	private AbsolutePanel _gamePanel;
	private Image _Froggit;
	private double _score;
	private int _missed;
	private int _right;
	
	private class IncommingActionsIterator implements Iterator<FroggitAction>{

		@Override
		public boolean hasNext() {
			return !_incommingActions.isEmpty();
		}

		@Override
		public FroggitAction next() {
			return _incommingActions.poll();
		}

		@Override
		public void remove() {
			//not used in this implementation
		}
		
	}
	
	public FroggitGame(){
		_world = new FroggitWorld();
		_incommingActions = new LinkedList<FroggitAction>();
		_passedActions = new ArrayList<FroggitAction>(10);
		_littleFrog = new FroggitMyFrog(_world.getStartPosition());
		_gamePanel = new AbsolutePanel();
		_gamePanel.add(getImageTableRepresentation());
		_Froggit = _littleFrog.getImage();
		_successListener = new LinkedList<SuccessHandler>();
		_score = 0;
		_missed = 0;
		_right = 0;
		initImageGUI();
		updateGUI();
		updateImageGUI();
	}
	public FroggitGame(FroggitWorld specificWorld){
		_world = specificWorld;
		_incommingActions = new LinkedList<FroggitAction>();
		_passedActions = new ArrayList<FroggitAction>(10);
		_littleFrog = new FroggitMyFrog(_world.getStartPosition());
		_gamePanel = new AbsolutePanel();
		_gamePanel.add(getImageTableRepresentation());
		_Froggit = _littleFrog.getImage();
		_successListener = new LinkedList<SuccessHandler>();
		_score = 0;
		_missed = 0;
		_right = 0;
		initImageGUI();
		updateGUI();
		updateImageGUI();
	}

	public void addNewAction(FroggitAction action){
		_incommingActions.add(action);
	}
	public FroggitReaction applyAction(){
		FroggitAction toapply = _incommingActions.poll();
		//first move the frog
		_littleFrog.applyAction(toapply);
		//then ask the world what happen during the move
		FroggitReaction reaction = _world.handleSuperpositionWith(_littleFrog);
		switch (reaction) {
		case Fail:
			_missed++;
			_littleFrog.returnToPreviousPosition();
			break;
		case Ok:
			//nice job !
			_right++;
			_passedActions.add(toapply);
			this.updateGUI();
			this.updateImageGUI();
			break;
		case Success:
			//nice job !
			_right++;
			_passedActions.add(toapply);
			this.updateGUI();
			this.updateImageGUI();
			//this.notifySuccess(); // do not call notifySuccess here -> otherwise win in once => 0 points (no score calculation ...)
			//stop the applyAll !!!
			break;
		default:
			break;
		}
		return reaction;
	}
	
	public void addSuccessHandler(SuccessHandler succ){
		_successListener.add(succ);
	}
	private void notifySuccess() {
		Iterator<SuccessHandler> ite = _successListener.iterator();
		while(ite.hasNext()){
			ite.next().onSuccess(this);
		}
	}


	@Override
	public String toString() {
		String toStr = "************************<br>";
		toStr += "Froggit position :"+_littleFrog.getPosition()+"<br>";
		toStr += "************************<br>";
		toStr += _world.toHTMLString();
		return toStr;
	}
	
	public FlexTable getTableRepresentation(){
		return _world.getTableRepresentation();
	}
	private void updateGUI(){
		FlexTable table = getTableRepresentation();
		Position pos = _littleFrog.getPosition();
		table.setText(pos.getY()+1, pos.getX()+1, "Froggit");
		Position previousPos = _littleFrog.getPreviousPosition();
		if(!pos.equals(previousPos)){
			table.setText(previousPos.getY()+1, previousPos.getX()+1, 
					_world.getCellString(previousPos.getX(), previousPos.getY()));
		}
	}
	private FlexTable getImageTableRepresentation(){
		return _world.getImageTableRepresentation();
	}
	public Panel getGamePanel(){
		return _gamePanel;
	}
	public void updateImageGUI(){
		FlexTable table = getImageTableRepresentation();
		Position pos = _littleFrog.getPosition();
		//first get the current image
		Widget cellWidget = table.getWidget(pos.getY()+1, pos.getX()+1);
		// and remove it form the table :
		int abs_left = cellWidget.getAbsoluteLeft();
		int abs_top = cellWidget.getAbsoluteTop();
		//System.out.println("Abspos = ("+abs_left+","+abs_top+")");
		
		int gp_left = _gamePanel.getAbsoluteLeft();
		int gp_top = _gamePanel.getAbsoluteTop();
		//System.out.println("AbsGP = ("+gp_left+","+gp_top+")");
		
		int froggit_left = abs_left - gp_left + 7;
		int froggit_top = abs_top - gp_top;
		_gamePanel.setWidgetPosition(_Froggit, froggit_left, froggit_top);
		
	}

	private void initImageGUI() {
		FlexTable table = getImageTableRepresentation();
		Position start = _world.getStartPosition();
		Widget cellWidget = table.getWidget(start.getX()+1, start.getY()+1);
		int abs_left = cellWidget.getAbsoluteLeft();
		int abs_top = cellWidget.getAbsoluteTop();
		
		int gp_left = _gamePanel.getAbsoluteLeft();
		int gp_top = _gamePanel.getAbsoluteTop();
		
		int froggit_left = abs_left - gp_left + 7;
		int froggit_top = abs_top - gp_top;
		_gamePanel.add(_Froggit,froggit_left,froggit_top);
	}
	
	public void validateAllActions() {
		Iterator<FroggitAction> ite = new IncommingActionsIterator();
		int length = 0;
		int oldMissedcount = _missed;
		int oldRightcount = _right;
		FroggitReaction react = null;
		while(ite.hasNext() && react != FroggitReaction.Success){
			react = applyAction();
			length++;//we don't use _incomming.size because we can stop in the middle of a sequence
			//System.out.println(react);
		}
		if(length !=0){
			_score += ((_right - oldRightcount)+3.0*(_missed - oldMissedcount))*3.0/(length*2.0);
			//System.out.println("score = "+_score+" \toldRC="+oldRightcount+" oldMR="+oldMissedcount+"\tr="+_right+" m="+_missed);
			//System.out.println("length = "+length+" computation="+((_right - oldRightcount)+3.0*(_missed - oldMissedcount))*3.0/(length*2.0));
		}else{
			//nothing
		}
		//if end of while due to a succes :
		if(react == FroggitReaction.Success){
			notifySuccess();
		}
		
	}

	public void removeAllActions() {
		//little tricky ... in order to remove all we create a new list :P
		_incommingActions = new LinkedList<FroggitAction>();
	}

	@SuppressWarnings("unchecked")
	public void removeLastAction() {
		int lastidx = _incommingActions.size();
		List<FroggitAction> toList = (List<FroggitAction>)_incommingActions;
		toList.remove(lastidx-1);
		//FroggitAction removed = toList.remove(lastidx-1);
		//System.out.println(removed);
	}
	
	
	public int getScore(){return ((int) (50*(Math.log(2*_score+1))*(1/(Math.log(_score+1)))));}
	public int getMissed(){return _missed;}
	public int getRight(){return _right;}
}
